
package com.wy.base;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import javax.persistence.Table;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.NumberUtils;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableBiMap;
import com.wy.annotation.Sort;
import com.wy.annotation.Unique;
import com.wy.result.Result;
import com.wy.result.ResultException;
import com.wy.utils.StrUtils;

/**
 * @apiNote
 * @author ParadiseWY
 * @date 2019年10月11日
 */
@SuppressWarnings("unchecked")
public abstract class AbstractService<T> {

	@Autowired
	private BaseMapper<T> baseMapper;

	private Class<T> clazz;

	public AbstractService() {
		ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
		Type type = parameterizedType.getActualTypeArguments()[0];
		clazz = (Class<T>) type;
	}

	public Class<T> getEntityClass() {
		return clazz;
	}

	public String getTableName() {
		if (clazz.isAnnotationPresent(Table.class)) {
			return clazz.getAnnotation(Table.class).name();
		}
		return null;
	}

	/**
	 * 新增值到数据库,null值不插入,默认值有
	 * 
	 * @param t 插入的实体类
	 * @return 是否成功
	 */
	@Transactional
	public Object create(T t) {
		Preconditions.checkNotNull(t);
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			// 检查是否有unique字段
			if (field.isAnnotationPresent(Unique.class)) {
				boolean hasValue = validUnique(field, t);
				if (hasValue) {
					throw new ResultException(field.getName() + "值重复,请重新输入");
				}
			}
			// 检查是否有排序字段
			if (field.isAnnotationPresent(Sort.class)) {
				long maxSort = validSort(field, t);
				if (maxSort == -1) {
					throw new ResultException("排序字段错误");
				} else {
					try {
						field.set(t, maxSort);
					} catch (IllegalArgumentException | IllegalAccessException e) {
						e.printStackTrace();
					}
				}
			}
		}
		return baseMapper.create(t);
	}

	private boolean validUnique(Field field, T model) {
		Unique unique = field.getAnnotation(Unique.class);
		String column = unique.value();
		if (StrUtils.isBlank(column)) {
			column = field.getName();
			if (unique.hump2Snake()) {
				column = StrUtils.hump2Snake(column);
			}
		}
		field.setAccessible(true);
		try {
			return hasValue(column, field.get(model));
		} catch (IllegalArgumentException | IllegalAccessException e) {
			e.printStackTrace();
		}
		return false;
	}

	private long validSort(Field field, T model) {
		field.setAccessible(true);
		try {
			Object value = field.get(model);
			if (Objects.nonNull(value) && Integer.parseInt(Objects.toString(value)) > 0) {
				return NumberUtils.parseNumber(field.get(model).toString(), Integer.class)
						.intValue();
			}
		} catch (IllegalArgumentException | IllegalAccessException e) {
			e.printStackTrace();
			return -1;
		}
		Sort sort = field.getAnnotation(Sort.class);
		String column = sort.value();
		if (StrUtils.isBlank(column)) {
			column = field.getName();
			if (sort.hump2Snake()) {
				column = StrUtils.hump2Snake(column);
			}
		}
		return baseMapper.getMax(column);
	}

	@Transactional
	public void creates(List<T> ts) {
		for (T t : ts) {
			create(t);
		}
	}

	/**
	 * 根据主键删除数据
	 * 
	 * @param pk 主键
	 * @return 影响的行数
	 */
	@Transactional
	public int delete(Serializable id) {
		Preconditions.checkNotNull(id);
		return baseMapper.delete(id);
	}

	@Transactional
	public int deletes(List<? extends Serializable> ids) {
		Preconditions.checkNotNull(ids);
		return baseMapper.deletes(ids);
	}

	@Transactional
	public int deletes(Map<String, Object> params) {
		Preconditions.checkNotNull(params);
		return baseMapper.deletes(params);
	}

	@Transactional
	public int modify(T record) {
		Preconditions.checkNotNull(record);
		return baseMapper.modify(record);
	}

	@Transactional
	public int modifyNotNull(T record) {
		Preconditions.checkNotNull(record);
		return baseMapper.modifyNotNull(record);
	}

	@Transactional
	public int modifySpecial(Map<String, Object> params) {
		Preconditions.checkNotNull(params);
		return baseMapper.modifySpecial(params);
	}

	public long getMax(String column) {
		Preconditions.checkNotNull(column);
		return baseMapper.getMax(column);
	}

	public Map<String, Object> getById(Serializable id) {
		Preconditions.checkNotNull(id);
		return baseMapper.getById(id);
	}

	public List<Map<String, Object>> getByIds(List<? extends Serializable> ids) {
		Preconditions.checkNotNull(ids);
		return baseMapper.getByIds(ids);
	}

	public Result<?> getEntitys(T model) {
		Preconditions.checkNotNull(model);
		if (model instanceof AbstractPage) {
			AbstractPage pager = (AbstractPage) model;
			if (!pager.hasPager()) {
				return Result.ok(baseMapper.getEntitys(model));
			} else {
				Page<Object> reuslt = PageHelper.startPage(pager.getPageIndex(),
						pager.getPageSize(), true);
				baseMapper.getEntitys(model);
				return Result.page(reuslt.getResult(), reuslt.getPageNum(), reuslt.getPageSize(),
						reuslt.getTotal());
			}
		} else {
			return Result.ok(baseMapper.getEntitys(model));
		}
	}

	public Result<?> getEntitys(Map<String, Object> params) {
		Preconditions.checkNotNull(params);
		if (Objects.isNull(params.get("pageIndex"))) {
			return Result.ok(baseMapper.getEntitys(params));
		} else {
			Page<Object> page = PageHelper.startPage(
					Integer.parseInt(params.get("pageIndex").toString()),
					Objects.isNull(params.get("pageSize")) ? 10
							: Integer.parseInt(params.get("pageSize").toString()),
					true);
			baseMapper.getList(params);
			return Result.page(page.getResult(), page.getPageNum(), page.getPageSize(),
					page.getTotal());
		}
	}

	/**
	 * 单表中多个字段是否有重复值,若有一个重复都返回true
	 * 
	 * @param params 参数列表,key:字段对应的java属性名,value:值
	 * @return
	 */
	public boolean hasValue(Map<String, Object> params) {
		Preconditions.checkNotNull(params);
		return getList(params).getTotal() > 0;
	}

	/**
	 * 单个表中某个字段是否有重复值
	 * 
	 * @param column 表字段对应的java属性
	 * @param value 需要查询的值
	 * @return 是否存在值,true是
	 */
	public boolean hasValue(String column, Object value) {
		Preconditions.checkNotNull(column);
		Preconditions.checkNotNull(value);
		return getList(ImmutableBiMap.of(column, value)).getTotal() > 0;
	}

	public Result<?> getList(Map<String, Object> params) {
		Preconditions.checkNotNull(params);
		if (Objects.isNull(params.get("pageIndex"))) {
			return Result.ok(baseMapper.getList(params));
		} else {
			Page<Object> page = PageHelper.startPage(
					Integer.parseInt(params.get("pageIndex").toString()),
					Objects.isNull(params.get("pageSize")) ? 10
							: Integer.parseInt(params.get("pageSize").toString()),
					true);
			baseMapper.getList(params);
			return Result.page(page.getResult(), page.getPageNum(), page.getPageSize(),
					page.getTotal());
		}
	}

	public Result<?> getList(AbstractPage page) {
		Preconditions.checkNotNull(page);
		if (!page.hasPager()) {
			return Result.ok(baseMapper.getList(page));
		} else {
			Page<Object> reuslt = PageHelper.startPage(page.getPageIndex(), page.getPageSize(),
					true);
			baseMapper.getList(page);
			return Result.page(reuslt.getResult(), reuslt.getPageNum(), reuslt.getPageSize(),
					reuslt.getTotal());
		}
	}
}